//===-- SystemZSubtarget.h - SystemZ subtarget information -----*- C++ -*--===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file declares the SystemZ specific subclass of TargetSubtargetInfo.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZSUBTARGET_H
#define LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZSUBTARGET_H

#include "SystemZFrameLowering.h"
#include "SystemZISelLowering.h"
#include "SystemZInstrInfo.h"
#include "SystemZRegisterInfo.h"
#include "SystemZSelectionDAGInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/TargetParser/Triple.h"
#include <string>

#define GET_SUBTARGETINFO_HEADER
#include "SystemZGenSubtargetInfo.inc"

namespace llvm {
class GlobalValue;
class StringRef;

class SystemZSubtarget : public SystemZGenSubtargetInfo {
  virtual void anchor();
protected:
// Bool members corresponding to the SubtargetFeatures defined in tablegen.
#define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, GETTER)                    \
  bool ATTRIBUTE = DEFAULT;
#include "SystemZGenSubtargetInfo.inc"

private:
  Triple TargetTriple;
  std::unique_ptr<SystemZCallingConventionRegisters> SpecialRegisters;
  SystemZInstrInfo InstrInfo;
  SystemZTargetLowering TLInfo;
  SystemZSelectionDAGInfo TSInfo;
  std::unique_ptr<const SystemZFrameLowering> FrameLowering;

  SystemZSubtarget &initializeSubtargetDependencies(StringRef CPU,
                                                    StringRef TuneCPU,
                                                    StringRef FS);
  SystemZCallingConventionRegisters *initializeSpecialRegisters();

public:
  SystemZSubtarget(const Triple &TT, const std::string &CPU,
                   const std::string &TuneCPU, const std::string &FS,
                   const TargetMachine &TM);

  SystemZCallingConventionRegisters *getSpecialRegisters() const {
    assert(SpecialRegisters && "Unsupported SystemZ calling convention");
    return SpecialRegisters.get();
  }

  template <class SR> SR &getSpecialRegisters() const {
    return *static_cast<SR *>(getSpecialRegisters());
  }

  const TargetFrameLowering *getFrameLowering() const override {
    return FrameLowering.get();
  }

  template <class TFL> const TFL *getFrameLowering() const {
    return static_cast<const TFL *>(getFrameLowering());
  }

  const SystemZInstrInfo *getInstrInfo() const override { return &InstrInfo; }
  const SystemZRegisterInfo *getRegisterInfo() const override {
    return &InstrInfo.getRegisterInfo();
  }
  const SystemZTargetLowering *getTargetLowering() const override {
    return &TLInfo;
  }
  const SelectionDAGTargetInfo *getSelectionDAGInfo() const override {
    return &TSInfo;
  }

  // True if the subtarget should run MachineScheduler after aggressive
  // coalescing. This currently replaces the SelectionDAG scheduler with the
  // "source" order scheduler.
  bool enableMachineScheduler() const override { return true; }

  // This is important for reducing register pressure in vector code.
  bool useAA() const override { return true; }

  // Always enable the early if-conversion pass.
  bool enableEarlyIfConversion() const override { return true; }

  // Enable tracking of subregister liveness in register allocator.
  bool enableSubRegLiveness() const override;

  // Automatically generated by tblgen.
  void ParseSubtargetFeatures(StringRef CPU, StringRef TuneCPU, StringRef FS);

// Getters for SubtargetFeatures defined in tablegen.
#define GET_SUBTARGETINFO_MACRO(ATTRIBUTE, DEFAULT, GETTER)                    \
  bool GETTER() const { return ATTRIBUTE; }
#include "SystemZGenSubtargetInfo.inc"

  // Return true if GV can be accessed using LARL for reloc model RM
  // and code model CM.
  bool isPC32DBLSymbol(const GlobalValue *GV, CodeModel::Model CM) const;

  bool isTargetELF() const { return TargetTriple.isOSBinFormatELF(); }

  // Returns TRUE if we are generating GOFF object code
  bool isTargetGOFF() const { return TargetTriple.isOSBinFormatGOFF(); }

  // Returns TRUE if we are using XPLINK64 linkage convention
  bool isTargetXPLINK64() const { return (isTargetGOFF() && isTargetzOS()); }

  // Returns TRUE if we are generating code for a s390x machine running zOS
  bool isTargetzOS() const { return TargetTriple.isOSzOS(); }
};
} // end namespace llvm

#endif
